package cn.com.idmy.cloud.config;


import lombok.RequiredArgsConstructor;
import org.aspectj.lang.annotation.Aspect;
import org.jetbrains.annotations.NotNull;
import org.springframework.aop.Advisor;
import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.context.annotation.Bean;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import org.springframework.transaction.interceptor.*;

import java.util.Collections;
import java.util.HashMap;

@Aspect
@RequiredArgsConstructor
@EnableTransactionManagement
public class DefaultTransactionConfig {
    private final TransactionManager transactionManager;

    @Bean
    @NotNull
    public TransactionInterceptor txAdvice() {
        var source = new NameMatchTransactionAttributeSource();

        var write = new RuleBasedTransactionAttribute();
        write.setRollbackRules(Collections.singletonList(new RollbackRuleAttribute(Exception.class)));
        write.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);

        var read = new RuleBasedTransactionAttribute();
        read.setReadOnly(true);
        read.setPropagationBehavior(TransactionDefinition.PROPAGATION_SUPPORTS);

        var txMap = new HashMap<String, TransactionAttribute>();
        for (var method : ServiceConfig.readTransactionalMethods) {
            txMap.put(method, read);
        }
        for (var method : ServiceConfig.writeTransactionalMethods) {
            txMap.put(method, write);
        }
        source.setNameMap(txMap);
        return new TransactionInterceptor(transactionManager, source);
    }

    @Bean
    @NotNull
    public Advisor txAdviceAdvisor() {
        var pointcut = new AspectJExpressionPointcut();
        pointcut.setExpression(ServiceConfig.transactionExpressionPointcut);
        return new DefaultPointcutAdvisor(pointcut, txAdvice());
    }
}
